
#ifndef SCHEDULER_H_
#define SCHEDULER_H_

#define INIT		0
#define SCHEDULE	1

#define ROUND_ROBIN				1
#define	MULTI_LEVEL				2
#define	THE_BEST_ALGO_IN_TOWN	3

#define REGULAR					1
#define EXTRA					2

#define NO_QUANTA				0
#define ROUND_ROBIN_QUANTA		3

#include <queue>
#include <stack>
#include "Worker.h"
#include "Thread_Table.h"
#include "OSScheduler.h"
#include "semaphore.h"

class Scheduler : OSScheduler {
public:
	Scheduler(vector<Worker*>* workers, Mailbox* shell_inbox);
	virtual ~Scheduler();
    void schedule(int mode);
    void setScheduling_algorithm(int scheduling_algorithm)
    {
        this->_scheduling_algorithm = scheduling_algorithm;
        schedule(INIT);
    }
    void beep();
    void setGot_revive_message(bool _got_revive_message)
    {
        this->_got_revive_message = _got_revive_message;
    }

    void setRound_robin_index(int _round_robin_index)
    {
        this->_round_robin_index = _round_robin_index;
    }

    Thread_Table *getThreads_table() const
    {
        return _threads_table;
    }

    void setIs_state_stabilized(bool _is_state_stabilized)
    {
        this->_is_state_stabilized = _is_state_stabilized;
    }

    bool getIs_state_stabilized() const
    {
        return _is_state_stabilized;
    }


    sem_t mutex;

private:
	vector<Worker*>* _workers;
	Mailbox*		_shell_inbox;
    Worker*			_next_thread_to_run;
    int 			_next_quantum;
    int 			_scheduling_algorithm;
    Thread_Table *	_threads_table;
    int 			_round_robin_index;
    bool			_is_state_stabilized;
    bool			_got_revive_message;

    // for statistics:
    int _the_number_of_context_switches_between_worker_threads;
    int _sum_of_message_quanta_given_to_all_worker_threads_from_last_initialization;
    int _the_actual_number_of_messages_passed_from_last_initialization;

    void init_RR_index();
    void advance_to_next_worker_RR();
    bool is_next_worker_blocked_or_killed();

    void set_all_workers_alive(bool alive_mode);
    void get_next_unblocked_worker();
    void do_context_switch(int flag);
    void round_robin(int mode, int flag);
    void multi_level(int mode);
    void the_best_algo(int mode);
    bool is_state_stabilized();
    int compute_quanta_to_give(int flag, bool double_quanta);
    void init_statistics_counters();

};

#endif /* SCHEDULER_H_ */
